Technical Q&A FL09
Ejecting the Volume on Which Your Program Resides


Q: I'm trying to programatically eject the floppy disk on which my application resides. I need to keep my application running while I programatically access another diskette, a process is similar to an installer. (That's how I know it can be done.) How do I avoid the "Please insert 'Name of Floppy Disk' " alert and keep my application running?

A: The problem is relatively simple to describe. If a program accesses an open file on an ejected volume, the system asks the user to insert the disk on which the volume resides. You can, of course, avoid making File Manager calls which read the disk. But resources are a different story.

The Mac OS application programming model assumes the availability of a resource file associated with the application. While your app is running, its resource fork is open, and from time to time resources are read from that file into memory. These resources may be read in for a number of reasons, including (but not necessarily limited to):

  • explicit calls to GetResource in your application code
  • 68K code segments which load implicitly because of an inter-segment subroutine call
  • Toolbox calls like GetNewWindow, which take an explicit parameter identifying the ID of a resource to be read
  • Toolbox calls like StandardOpenDialog, which take no explicit parameters identifying a resource, but do indeed read resources from the current application's resource file
  • many, many Toolbox calls which implicitly need to read unspecified resources from the System file and other files in the System Folder (this is only relevant if the volume on which your program resides is also the boot volume, which is uncommon today)

Unfortunately, it's not possible to overcome this design assumption in any straightforward way. There's no call you can make that tells the system "Stop loading resources for a while now, please." Even if there were, much of the rest of the Toolbox would stop working.

If you don't need to eject the boot volume, then you could index, load, and mark unpurgeable every resource in your application resource fork before ejecting the volume on which your application resides, but this might require a prohibitive amount of memory.

A more optimized technique might be to identify which resources are loaded by your application and, before ejecting the volume, make sure those resources are loaded (and not purgeable). Maintaining this list of resources may require a prohibitive amount of tedium: You may need to do a fair amount of debugger work, probably involving setting A-trap and TVector breaks on calls which cause resources to be read from the disk, such as GetResource, LoadResource, ReadPartialResource, etc. Also, the list of resources which must be loaded may well change quite often as your code evolves.

Unfortunately, there are some portions of the Toolbox which are very tricky to support in this kind of program. There are a few Toolbox calls which implicitly purge or detach resources. For example, disposing a pop-up menu control on certain versions of the system will release the MENU resource. If the user can re-open a window which contains such a control, this presents a problem, because the diskette has already been ejected, and there is no place from which to load the MENU resource data. Your options here are limited: you can avoid the problem Toolbox call entirely or find another way (write your own code) to achieve the same effect. There is no list of Toolbox calls that have this behavior, and the behavior will vary on a case-by-case basis.

If you need to eject the boot volume, your task will be quite daunting, and will not yield results which will work into the indefinite future, since the implementation of Toolbox calls can change, and the resources they must load implicitly can likewise change. There is no list of resources you must load, and there is no programmatic way to determine which resources are used by which Toolbox call. Here's a testimonial from Apple's Installer Tech Lead about his team's experience dealing with this aspect of the problem:

Generally, each new release of system software requires additional resources to be pre-loaded from the System file. Every time we see a new disk swap dialog, we use MacsBug to step back through the call chain until we find the culprit. This is why we always store the list of System resources to pre-load in a resource in the application instead of hard-coding it. If I were a third-party developer, I'd probably store the list in a separate file to make it easier to update.

Another complicating factor is system extensions, including but not limited to virus protection software. Some of these extensions need to get information about the current application in ways which cause disk access. This is one of the reasons why some installers warn the user to boot with extensions disabled (hold the shift key down during boot) before performing an installation.

The bottom line here is that the system's programming model is in direct conflict with what you are trying to do. We'd like to be able to provide a simple way to compensate, but this is a deeply-ingrained design limitation we cannot lift in the forseeable future. What you are trying to do is not impossible, but it's going to be a lot of work.

[Jul 06 1998]


Developer Documentation | Technical Notes | Development Kits | Sample Code